package com.ccf.business.knowledge.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ccf.business.knowledge.model.vo.LabelDataVO;
import com.ccf.business.knowledge.model.vo.LabelTaskVO;
import com.google.common.collect.Lists;
import com.common.utils.constant.Constants;
import com.framework.dubbo.consumer.service.DubboService;
import com.ccf.business.knowledge.client.SourceClient;
import com.ccf.business.knowledge.mapper.LabelDataMapper;
import com.ccf.business.knowledge.model.LabelData;
import com.ccf.business.knowledge.model.LabelTask;
import com.ccf.business.knowledge.model.vo.*;
import com.ccf.business.knowledge.service.ILabelDataEntityService;
import com.ccf.business.knowledge.service.ILabelDataRelationService;
import com.ccf.business.knowledge.service.ILabelDataService;
import com.ccf.business.knowledge.service.ILabelTaskService;
import com.common.model.pojo.Order;
import com.common.model.pojo.Query;
import com.common.model.result.CodeEnum;
import com.common.model.result.PageResult;
import com.service.mybatis.service.impl.SuperServiceImpl;
import com.service.mybatis.util.Condition;
import com.service.websocket.handler.MessageHandler;
import com.service.websocket.to.User;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 标注记录
 *
 * @author ccf
 * @date 2022-02-15 16:56:10
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class LabelDataServiceImpl extends SuperServiceImpl<LabelDataMapper, LabelData> implements ILabelDataService {

    private ILabelTaskService labelTaskService;

    /**
     * 避免循环注入 使用set注入
     * @param labelTaskService
     */
    @Autowired
    public void setLabelTaskService(ILabelTaskService labelTaskService) {
        this.labelTaskService = labelTaskService;
    }

    private final SourceClient sourceClient;

    private final DubboService dubboService;

    private final ILabelDataEntityService iLabelDataEntityService;

    private final ILabelDataRelationService iLabelDataRelationService;

    private final MessageHandler messageHandler;

    /**
    * 列表
    * @param query
    * @return
    */
    @Override
    public PageResult<LabelData> findList(Query query){
        //默认按照标注状态排序
        if (CollUtil.isEmpty(query.filterNullOrders())){
            query.setOrders(Lists.newArrayList(new Order("status", true),
                    new Order("update_time", false)));
        }
        QueryWrapper<LabelData> queryWrapper = Condition.getQueryWrapperAndUserName(query, "tager");
        Page<LabelData> page = page(Condition.getPage(query), queryWrapper);
        return PageResult.<LabelData>builder().datas(page.getRecords()).code(CodeEnum.SUCCESS.getCode()).count(page.getTotal()).build();
    }



    @Override
    public PageResult labelList(Query query) {

        String taskId = query.getParams().get("taskId");
        LabelTask task = labelTaskService.getById(taskId);
        if (task == null){
            throw new RuntimeException("参数错误：taskId不存在");
        }
        //均分标注 过滤数据
        if (LabelTask.AVG.equalsIgnoreCase(task.getLabelWay())) {
            String userId = MDC.get(Constants.USER_ID);
            query.getParams().put("tager", userId);
        }
        return findList(query);
    }

    @Override
    public LabelDataVO detail(String id) {

        LabelData labelData = getById(id);
        if (labelData ==null){
            throw new RuntimeException("数据不存在");
        }
        LabelDataVO labelDataVO = new LabelDataVO(labelData);
        String viewPath = sourceClient.getViewPath(labelData.getSourceId());
        viewPath = StrUtil.removeAll(viewPath, Constants.DOUBLE_QUOTATION);
        labelDataVO.setViewPath(viewPath);
        LabelTask task = labelTaskService.getById(labelData.getTaskId());
        labelDataVO.setLabelType(task.getLabelType());
        labelDataVO.setLabelWay(task.getLabelWay());
        labelDataVO.setTaskStatus(task.getStatus());
        labelDataVO.setEntityTypeList(iLabelDataEntityService.entityList(id));
        labelDataVO.setRelationTypeList(iLabelDataRelationService.relationList(id));
        return labelDataVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public LabelData  saveAndLabel(LabelDataVO labelData, Integer status) {
        LabelData byId = getById(labelData.getId());
        byId.setStatus(status);
        String userId = MDC.get(Constants.USER_ID);
        if (LabelData.WAITING_AUDIT == status){
            byId.setTager(userId);
            byId.setTagTime(new Date());
        }
        if (LabelData.COMPLETED == status){
            byId.setAuditor(userId);
            byId.setAuditTime(new Date());
        }
        saveOrUpdate(byId);
        iLabelDataEntityService.saveOrUpdateBatch(labelData);
        iLabelDataRelationService.saveOrUpdateBatch(labelData);
        return byId;
    }

    @Override
    public void submit(LabelDataVO labelData) {

        LabelData label = saveAndLabel(labelData, LabelData.WAITING_AUDIT);

        List<LabelData> list = list(Wrappers.<LabelData>query()
                .lambda().eq(LabelData::getTaskId, label.getTaskId()));
        //都满足 修改状态
        if (CollUtil.isNotEmpty(list) && list.stream().allMatch(e->e.getStatus() == LabelData.WAITING_AUDIT)){
            labelTaskService.change(label.getTaskId(), LabelTask.AUDIT);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void recall(LabelData labelData) {
        LabelData byId = getById(labelData.getId());
        int beforeStatus = byId.getStatus() - 1;
        String taskId = byId.getTaskId();
        if (LabelData.TAGGING == beforeStatus){
            byId.setTagTime(null);
            labelTaskService.change( taskId, LabelTask.TAGGING);
        } else if (LabelData.WAITING_AUDIT == beforeStatus){
            byId.setAuditor(null);
            byId.setAuditTime(null);
            labelTaskService.change( taskId, LabelTask.AUDIT);
        } else {
            throw new RuntimeException("已经撤回了");
        }
        byId.setStatus(beforeStatus);
        saveOrUpdate(byId);
    }

    @Override
    public void audit(LabelDataVO labelData) {

        LabelData label = saveAndLabel(labelData, LabelData.COMPLETED);

        List<LabelData> list = list(Wrappers.<LabelData>query()
                .lambda().eq(LabelData::getTaskId, label.getTaskId()));
        //都满足 修改状态
        if (CollUtil.isNotEmpty(list) && list.stream().allMatch(e->e.getStatus() == LabelData.COMPLETED)){
            labelTaskService.change( label.getTaskId(), LabelTask.COMPLETE);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void auditAll(LabelDataVO labelData) {
        String taskId = labelData.getTaskId();
        List<LabelData> list = list(Wrappers.<LabelData>query()
                .lambda().eq(LabelData::getTaskId, taskId));
        //都满足 修改状态
        if (CollUtil.isNotEmpty(list) ){
            String userId = MDC.get(Constants.USER_ID);
            for (LabelData byId : list) {
                byId.setStatus(LabelData.COMPLETED);
                byId.setAuditor(userId);
                byId.setAuditTime(new Date());
                saveOrUpdate(byId);
            }
            labelTaskService.change(taskId, LabelTask.COMPLETE);
        }

    }

    @Override
    public String next(String id, Integer status) {
        LabelData byId = getById(id);
        LabelTask task = labelTaskService.getById(byId.getTaskId());
        String nid = null;
        if (LabelTask.AVG.equalsIgnoreCase(task.getLabelWay())){
            nid = baseMapper.selectAfterIdByRankAndUser(id, status);
        } else {
            nid = baseMapper.selectAfterIdByRank(id, status);
        }
        if (nid == null || nid.equalsIgnoreCase(id)){
            nid = baseMapper.selectMinIdByRank(id, status);
        }
        return nid;
    }

    /**
     * 保存数据
     * @param labelTask
     * @param files
     * @param users
     */
    @Override
    public void saveDatas(LabelTaskVO labelTask, String[] files, String[] users, boolean isUpdate) {

        String id = labelTask.getId();
        List<LabelData> datas = Lists.newArrayList();
        Map<String, String> dataPathMap = sourceClient.getDataPathMap();
        Map<String, String> dataNameMap = sourceClient.getNameMap();
        if (dataPathMap == null){
            throw new RuntimeException("获取文件内容失败");
        }
        for (int i = 0; i < files.length; i++) {
            String sid = files[i];
            LabelData labelData = new LabelData();
            labelData.setSourceId(sid);
            labelData.setTaskId(id);
            //均分 先分配人
            labelData.setTager(LabelTask.AVG.equalsIgnoreCase(labelTask.getLabelWay())? users[i%users.length]: null);
            labelData.setSerial(i + 1);
            labelData.setStatus(LabelData.TAGGING);
            try {
                String dataPath = dataPathMap.get(sid);
                labelData.setFileName(dataNameMap.get(sid));
                String context = dubboService.file2Str(dataPath);
                labelData.setData(context);
                labelData.setPath(dataPath);
            } catch (Exception e) {
                e.printStackTrace();
            }
            datas.add(labelData);
        }
        if (datas.size() > 0 ){
            if (isUpdate){
                List<LabelData> oldDatas = list(Wrappers.<LabelData>query()
                        .lambda().eq(LabelData::getTaskId, id));
                if (CollUtil.isNotEmpty(oldDatas)){
                    removeByIds(oldDatas.stream().map(e->e.getId()).collect(Collectors.toList()));
                }
            }
            saveBatch(datas);
        }
    }

    @Override
    public User checkLocks(String id) {
        //判断是否被占用
        User user = messageHandler.isExitsBusId(id);
        String userId = MDC.get(Constants.USER_ID);
        if (user != null && !userId.equalsIgnoreCase(user.getUserId())) {
            return user;
        }
        return null;

    }

    @Override
    public User getLocksById(String id) {
        LabelData byId = getById(id);
        if (byId == null){
            return null;
        }
        User user = messageHandler.isExitsBusId(id);
        return user;

    }
}
